package roborally.usableitems;

import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Immutable;
import be.kuleuven.cs.som.annotate.Raw;
import roborally.itemsonboard.BoardItem;
import roborally.itemsonboard.Robot;
import roborally.supporting.PhysicalAmount;
import roborally.supporting.Terminatable;

/**
 * This interface specifies usable items. An item can be picked up, used and dropped. All methods are implemented
 * nominal. There are checkers specified on which conditions an object can be used.
 * 
 * 
 * @author Molderez Tom, 2de bach Ingenieurswetenschappen Computerwetenschappen-Elektrotechniek and Reniers Jorn, 2de bach Ingenieurswetenschappen Werktuigkunde-Computerwetenschappen
 * @version 2.0
 */
public interface Usable extends Comparable<Usable>, Terminatable, BoardItem {
	
	/**
	 * Returns the weight of this battery.
	 */
	@Basic @Raw @Immutable	
	public abstract PhysicalAmount getWeight();
	
	/**
	 * Let the robot pick up this usable, if possible.
	 * 
	 * @param robot The robot that should pick up this usable.
	 * @pre
	 * 		| robot != null
	 * @pre 
	 * 		| robot.canPickUp(this)
	 * @pre
	 * 		| !isTerminated()
	 * @post
	 * 		| !robot.getBoard().contains(this)
	 */
	public abstract void isPickedUp(Robot<? extends Usable> robot);
	
	/**
	 * The usable will be used by the robot. The specified effect depends of the implementing class.
	 * 
	 * @param robot The robot to which the energy of this battery must go.
	 * @pre
	 * 		| robot != null
	 * @pre 
	 * 		| robot.canUse(this)
	 * @pre
	 * 		| !isTerminated()
	 */
	public abstract void isUsed(Robot<? extends Usable> robot);
	
	/**
	 * Let the robot drop this usable, if possible.
	 * 
	 * @param robot The robot that should drop this usable.
	 * @pre
	 * 		| robot != null
	 * @pre 
	 * 		| robot.canDrop(this)
	 * @pre
	 * 		| !isTerminated()
	 * @effect 
	 * 		| if robot.getBoard() != null
	 * 		|	then robot.getBoard().addAsItem(this)
	 * @post
	 * 		| if robot.getBoard() == null
	 * 		|	this.getBoard() == null
	 * @post
	 * 		| this.getPosition() == robot.getPosition()
	 * @note The robot will leave this method in a raw state because this usable will have a board and
	 * a position, and the robot will possess this battery.
	 */
	@Raw
	public abstract void isDropped(Robot<? extends Usable> robot);
	
	/**
	 * Compares the usable to this one.
	 * 
	 * @return
	 * 		| result == this.getWeight().compareTo(usable.getWeight())
	 * @throws IllegalArgumentException
	 * 		| usable == null
	 */
	@Override
	public abstract int compareTo(Usable usable) throws IllegalArgumentException;
		
}
